package com.yyfax.pay.depository.service.inner.impl;

import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import javax.annotation.Resource;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.yyfax.commons.http.HttpUtil;
import com.yyfax.commons.lang.DateUtil;
import com.yyfax.framework.common.Log;
import com.yyfax.framework.yyfax.CryptUtil;
import com.yyfax.pay.common.enums.FuiouDepositRspCodeEnum;
import com.yyfax.pay.common.enums.FuiouDepositStateEnum;
import com.yyfax.pay.common.exception.PayException;
import com.yyfax.pay.common.exception.PayExceptionCode;
import com.yyfax.pay.common.model.vo.PayRspCodeVO;
import com.yyfax.pay.common.util.FuiouSignUtil;
import com.yyfax.pay.depository.dao.FuiouChangeCardDao;
import com.yyfax.pay.depository.dao.FuiouChargeDao;
import com.yyfax.pay.depository.dao.FuiouFrozenAppropriateDao;
import com.yyfax.pay.depository.dao.FuiouFrozenDao;
import com.yyfax.pay.depository.dao.FuiouFrozenToFrozenDao;
import com.yyfax.pay.depository.dao.FuiouFrozenTransferDao;
import com.yyfax.pay.depository.dao.FuiouTransferMerchantUserDao;
import com.yyfax.pay.depository.dao.FuiouTransferUserUserDao;
import com.yyfax.pay.depository.dao.FuiouUnfrozenDao;
import com.yyfax.pay.depository.dao.FuiouUserRegisterDao;
import com.yyfax.pay.depository.dao.FuiouWithdrawDao;
import com.yyfax.pay.depository.domain.FuiouChangeCard;
import com.yyfax.pay.depository.domain.FuiouCharge;
import com.yyfax.pay.depository.domain.FuiouFrozen;
import com.yyfax.pay.depository.domain.FuiouFrozenAppropriate;
import com.yyfax.pay.depository.domain.FuiouFrozenToFrozen;
import com.yyfax.pay.depository.domain.FuiouFrozenTransfer;
import com.yyfax.pay.depository.domain.FuiouTransferMerchantUser;
import com.yyfax.pay.depository.domain.FuiouTransferUserUser;
import com.yyfax.pay.depository.domain.FuiouUnfrozen;
import com.yyfax.pay.depository.domain.FuiouUserRegister;
import com.yyfax.pay.depository.domain.FuiouWithdraw;
import com.yyfax.pay.depository.service.inner.FuiouChangeCardService;
import com.yyfax.pay.depository.service.inner.FuiouQueryService;
import com.yyfax.pay.depository.vo.FuiouResponseVO;
import com.yyfax.pay.depository.vo.QueryChangeCardVO;
import com.yyfax.pay.depository.vo.QueryChargeWithdrawVO;
import com.yyfax.pay.depository.vo.TradeQueryVO;
import com.yyfax.pay.depository.vo.UserRegisterVO;
import com.yyfax.pay.third.facade.fuioudeposit.FuiouDepositService;
import com.yyfax.pay.third.facade.fuioudeposit.FuiouSignService;
import com.yyfax.pay.third.model.to.fuioudeposit.FuiouDepositConfigExt;
import com.yyfax.pay.third.model.to.fuioudeposit.FuiouQueryTransferChargeReq;
import com.yyfax.pay.third.model.to.fuioudeposit.FuiouQueryUserInfoReq;
import com.yyfax.pay.third.model.to.fuioudeposit.QueryTransferChargeResultXMLRsp;
import com.yyfax.pay.third.model.to.fuioudeposit.TradeQueryResultXMLRsp;
import com.yyfax.pay.third.model.to.fuioudeposit.xml.ChargeWithdrawPlain;
import com.yyfax.pay.third.model.to.fuioudeposit.xml.RootXMLRsp;
import com.yyfax.pay.third.model.to.fuioudeposit.xml.UserChangeCardPlain;
import com.yyfax.pay.third.model.to.fuioudeposit.xml.UserInfoPlain;
import com.yyfax.pay.third.model.to.fuioudeposit.xml.UserInfoPlain.UserInfoResult;
import com.yyfax.pay.vo.depository.QueryChangeCardReq;
import com.yyfax.pay.vo.depository.QueryChargeWithdrawReq;
import com.yyfax.pay.vo.depository.QueryTradeReq;
import com.yyfax.pay.vo.depository.QueryTransferChargeReq;
import com.yyfax.pay.vo.depository.QueryTransferChargeRsp;
import com.yyfax.pay.vo.depository.QueryUserInfoReq;
import com.yyfax.pay.vo.depository.TradeType;

/**
 * @author yejc
 * @date 2017-09-08
 * @since v1.0.0
 */
@Service
public class FuiouQueryServiceImpl implements FuiouQueryService {
	private static final Logger logger = LoggerFactory.getLogger(FuiouQueryServiceImpl.class);

	@Resource
	private FuiouSignService fuiouSignService;
	@Resource
	private FuiouDepositService fuiouDepositService;
	@Resource
	private FuiouWithdrawDao fuiouWithdrawDao;
	@Resource
	private FuiouChargeDao fuiouChargeDao;
	@Resource
	private FuiouChangeCardDao changeCardDao;
	@Resource
	private FuiouTransferMerchantUserDao transferMerchantUserDao;
	@Resource
	private FuiouTransferUserUserDao transferUserUserDao;
	@Resource
	private FuiouFrozenTransferDao frozenTransferDao;
	@Resource
	private FuiouFrozenAppropriateDao frozenAppropriateDao;
	@Resource
	private FuiouFrozenDao frozenDao;
	@Resource
	private FuiouUnfrozenDao unfrozenDao;
	@Resource
	private FuiouFrozenToFrozenDao frozenToFrozenDao;
	@Resource
	private FuiouChangeCardService fuiouChangeCardService;
	@Resource
	private FuiouUserRegisterDao userRegisterDao;
	@Resource
	private FuiouDepositRegisterServiceImpl registerService;

	private TypeReference<Map<String, String>> strKV = new TypeReference<Map<String, String>>() {
	};

	private static final int CONNECT_TIMEOUT = 30000;

	private static final int READ_TIMEOUT = 30000;

	/** 转账充值查询交易名称 */
	private static final String QUERY_TRANSFER_CHARGE_TRAN_NAME = "XXCZ";
	/** 转账充值查询流水号前缀 */
	private static final String QUERY_TRANSFER_CHARGE_BUSI_ID_PRE = "QTC";

	@Override
	public ChargeWithdrawPlain queryChargeWithdraw(String merchantCode, QueryChargeWithdrawReq params) {
		FuiouDepositConfigExt extInfo = fuiouSignService.getFuiouDepositConfig(merchantCode);
		// 构建请求参数
		QueryChargeWithdrawVO vo = buildReqParams(merchantCode, params, extInfo);

		FuiouResponseVO resp = fuiouDepositService.postForResponseVO(vo, extInfo.getQueryChargeWithdrawUrl(), merchantCode);
		if (!resp.getResult().equals(FuiouResponseVO.NORMAL)) {
			throw PayExceptionCode.QUERY_ERROR.exp();
		}
		RootXMLRsp<ChargeWithdrawPlain> rsp = (RootXMLRsp<ChargeWithdrawPlain>) RootXMLRsp.fromXml(resp.getContent(), ChargeWithdrawPlain.class);

		ChargeWithdrawPlain plain = rsp.getPlain();

		for (ChargeWithdrawPlain.ChargeWithdrawResult chargeWithdrawResult : plain.getResults()) {
			// 转异常码
			PayRspCodeVO expCode = fuiouDepositService.converToPayRspCode(chargeWithdrawResult.getTxn_rsp_cd());
			chargeWithdrawResult.setRspCode(expCode.getCode());
			chargeWithdrawResult.setRspMsg(expCode.getDesc());
			// 恶心的需求，要返回业务订单号
			if (TradeType.CHARGE == params.getType()) {
				if (StringUtils.isBlank(chargeWithdrawResult.getBusiId())) {
					continue;
				}
				FuiouCharge charge = fuiouChargeDao.selectByBusiId(chargeWithdrawResult.getBusiId());
				chargeWithdrawResult.setOrderId(charge == null ? "" : charge.getOrderId());
			} else if (TradeType.WITHDRAW == params.getType()) {
				if (StringUtils.isBlank(chargeWithdrawResult.getBusiId())) {
					continue;
				}
				FuiouWithdraw withdraw = fuiouWithdrawDao.selectByPrimaryKey(chargeWithdrawResult.getBusiId());
				chargeWithdrawResult.setOrderId(withdraw == null ? "" : withdraw.getOrderId());
			}
		}
		return plain;
	}

	private QueryChargeWithdrawVO buildReqParams(String merchantCode, QueryChargeWithdrawReq params, FuiouDepositConfigExt extInfo) {
		final String op = "FuiouQueryServiceImpl.buildReqParams";

		QueryChargeWithdrawVO vo = new QueryChargeWithdrawVO();
		vo.setVersion(extInfo.getVersion());
		vo.setMerchantId(extInfo.getMerchantId());
		vo.setQueryBusiId(String.valueOf(System.nanoTime()));
		if (StringUtils.isNotBlank(params.getOrderId())) {
			if (TradeType.CHARGE == params.getType()) {
				// 充值查询
				FuiouCharge charge = fuiouChargeDao.selectByMerchantCodeAndOrderId(merchantCode, params.getOrderId());
				if (charge == null) {
					logger.warn(Log.op(op).msg("充值订单不存在").kv("merchantCode", merchantCode).kv("orderId", params.getOrderId()).toString());
					throw PayExceptionCode.ORDER_NOT_FOUND.exp();
				}
				vo.setBusiId(charge.getBusiId());
			} else if (TradeType.WITHDRAW == params.getType()) {
				// 提现查询
				FuiouWithdraw withdraw = fuiouWithdrawDao.selectByOrderIdMerchantCode(params.getOrderId(), merchantCode);
				if (withdraw == null) {
					logger.warn(Log.op(op).msg("提现订单不存在").kv("merchantCode", merchantCode).kv("orderId", params.getOrderId()).toString());
					throw PayExceptionCode.ORDER_NOT_FOUND.exp();
				}
				vo.setBusiId(withdraw.getBusiId());
			}
		}

		vo.setType(params.getType().getCode());
		vo.setStartTime(params.getStartTime());
		vo.setEndTime(params.getEndTime());
		vo.setAccountNo(params.getAccountNo());
		vo.setState(params.getState());
		vo.setPageNo(params.getPageNo() == null ? "" : params.getPageNo().toString());
		vo.setPageSize(params.getPageSize() == null ? "" : params.getPageSize().toString());
		vo.setSignature(fuiouSignService.getSign(merchantCode, vo));
		return vo;
	}

	@Override
	public UserChangeCardPlain queryChangeCard(String merchantCode, QueryChangeCardReq params) {
		FuiouChangeCard order = changeCardDao.selectByOrderIdMerchantCode(params.getOrderId(), merchantCode);
		if (order == null) {
			throw PayExceptionCode.ORDER_NOT_FOUND.exp();
		}

		UserChangeCardPlain response = new UserChangeCardPlain();
		if (order.getState().equals(FuiouDepositStateEnum.ACCEPTED.getValue())) {
			// 已受理的订单才去查询富友
			FuiouDepositConfigExt extInfo = fuiouSignService.getFuiouDepositConfig(merchantCode);

			QueryChangeCardVO vo = buildReqParams(order, extInfo);

			FuiouResponseVO resp = fuiouDepositService.postForResponseVO(vo, extInfo.getQueryChangeCardUrl(), merchantCode);
			if (!resp.getResult().equals(FuiouResponseVO.NORMAL)) {
				throw PayExceptionCode.QUERY_ERROR.exp();
			}

			RootXMLRsp<UserChangeCardPlain> rsp = (RootXMLRsp<UserChangeCardPlain>) RootXMLRsp.fromXml(resp.getContent(), UserChangeCardPlain.class);
			if (!FuiouDepositRspCodeEnum.SUCCESS.getValue().equals(rsp.getPlain().getRspCode())) {
				throw PayExceptionCode.QUERY_ERROR.expMsg(rsp.getPlain().getRspMsg());
			}

			if (Objects.equals("1", rsp.getPlain().getExamineState())) {
				changeCardDao.updateStateAndRspByBusiId(FuiouDepositStateEnum.SUCCESS.getValue(), order.getBusiId(), DateUtil.getCurrentDateTime(),
						PayExceptionCode.SUCCESS.getCode(), "审核通过");
				try {
					fuiouChangeCardService.updateUserPaymentBankCard(merchantCode, order.getMerchantUserId(),
							CryptUtil.decrypt(order.getCardNoCip()));
				} catch (Exception e) {

				}
			} else if (Objects.equals("2", rsp.getPlain().getExamineState())) {
				changeCardDao.updateStateAndRspByBusiId(FuiouDepositStateEnum.FAIL.getValue(), order.getBusiId(), DateUtil.getCurrentDateTime(),
						PayExceptionCode.ERROR_PAY_FAIL.getCode(), rsp.getPlain().getRemark());
			}
			response.setExamineState(rsp.getPlain().getExamineState());
			response.setRemark(rsp.getPlain().getRemark());
		} else if (order.getState().equals(FuiouDepositStateEnum.FAIL.getValue())) {
			// 失败订单，可能由于通知修改或之前查询为审核失败，直接返回审核状态为失败
			response.setExamineState("2");
			response.setRemark(order.getRespDesc());
		} else if (order.getState().equals(FuiouDepositStateEnum.SUCCESS.getValue())) {
			// 成功订单，可能由于通知修改或之前查询为审核成功，直接返回审核状态为成功
			response.setExamineState("1");
			response.setRemark(order.getRespDesc());
		}

		response.setAccountNo(order.getAccountNo());
		return response;
	}

	@Override
	public UserInfoPlain queryUserInfo(String merchantCode, QueryUserInfoReq params) {
		FuiouDepositConfigExt extInfo = fuiouSignService.getFuiouDepositConfig(merchantCode);
		// 构建请求参数
		FuiouQueryUserInfoReq vo = buildQueryUserInfoVO(merchantCode, params, extInfo);
		// 发请求
		FuiouResponseVO resp = fuiouDepositService.postForResponseVO(vo, extInfo.getQueryUserInfoUrl(), merchantCode);
		if (!resp.getResult().equals(FuiouResponseVO.NORMAL)) {
			throw PayExceptionCode.QUERY_ERROR.exp();
		}
		// 解析响应结果
		RootXMLRsp<UserInfoPlain> rsp = (RootXMLRsp<UserInfoPlain>) RootXMLRsp.fromXml(resp.getContent(), UserInfoPlain.class);
		return rsp.getPlain();
	}

	@Override
	public TradeQueryResultXMLRsp.TradePlain queryTrade(String merchantCode, QueryTradeReq params) {
		FuiouDepositConfigExt extInfo = fuiouSignService.getFuiouDepositConfig(merchantCode);
		// 构建请求参数
		TradeQueryVO vo = buildTradeQueryReqParams(merchantCode, params, extInfo);

		FuiouResponseVO resp = fuiouDepositService.postForResponseVO(vo, extInfo.getTradeQueryUrl(), merchantCode);
		if (!resp.getResult().equals(FuiouResponseVO.NORMAL)) {
			throw PayExceptionCode.QUERY_ERROR.exp();
		}
		TradeQueryResultXMLRsp rsp = TradeQueryResultXMLRsp.fromXml(resp.getContent());
		TradeQueryResultXMLRsp.TradePlain plain = rsp.getPlain();
		for (TradeQueryResultXMLRsp.TradeQueryRst tradeQueryRst : plain.getResults()) {
			// 转异常码
			PayRspCodeVO expCode = fuiouDepositService.converToPayRspCode(tradeQueryRst.getTradeRespCode());
			tradeQueryRst.setRspCode(expCode.getCode());
			tradeQueryRst.setRspMsg(expCode.getDesc());
		}
		return plain;
	}

	private TradeQueryVO buildTradeQueryReqParams(String merchantCode, QueryTradeReq params, FuiouDepositConfigExt extInfo) {
		TradeQueryVO vo = new TradeQueryVO();
		vo.setMerchantId(extInfo.getMerchantId());
		vo.setMerchantSerialNo(String.valueOf(System.nanoTime()));
		String orderId = params.getOrderId();
		if (StringUtils.isNotBlank(orderId)) {
			switch (params.getType()) {
			// 转账:
			case TRANSFER: {
				FuiouTransferMerchantUser order = transferMerchantUserDao.selectByOrderIdMerchantCode(orderId, merchantCode);
				if (order == null) {
					throw PayExceptionCode.ORDER_NOT_FOUND.exp();
				}
				vo.setBusiId(order.getBusiId());
				break;
			}
			// 划拨:
			case APPROPRIATE: {
				FuiouTransferUserUser order = transferUserUserDao.selectByOrderIdMerchantCode(orderId, merchantCode);
				if (order == null) {
					throw PayExceptionCode.ORDER_NOT_FOUND.exp();
				}
				vo.setBusiId(order.getBusiId());
				break;
			}
			// 转账冻结:
			case TRANSFER_FROZEN: {
				FuiouFrozenTransfer order = frozenTransferDao.selectByOrderIdMerchantCode(orderId, merchantCode);
				if (order == null) {
					throw PayExceptionCode.ORDER_NOT_FOUND.exp();
				}
				vo.setBusiId(order.getBusiId());
				break;
			}
			// 划拨冻结:
			case APPROPRIATE_FROZEN: {
				FuiouFrozenAppropriate order = frozenAppropriateDao.selectByOrderIdMerchantCode(orderId, merchantCode);
				if (order == null) {
					throw PayExceptionCode.ORDER_NOT_FOUND.exp();
				}
				vo.setBusiId(order.getBusiId());
				break;
			}
			// 冻结:
			case FROZEN: {
				FuiouFrozen order = frozenDao.selectByOrderIdMerchantCode(orderId, merchantCode);
				if (order == null) {
					throw PayExceptionCode.ORDER_NOT_FOUND.exp();
				}
				vo.setBusiId(order.getBusiId());
				break;
			}
			// 解冻:
			case UNFROZEN: {
				FuiouUnfrozen order = unfrozenDao.selectByOrderIdMerchantCode(orderId, merchantCode);
				if (order == null) {
					throw PayExceptionCode.ORDER_NOT_FOUND.exp();
				}
				vo.setBusiId(order.getBusiId());
				break;
			}
			// 冻结付款到冻结:
			case FROZEN_TO_FROZEN: {
				FuiouFrozenToFrozen order = frozenToFrozenDao.selectByOrderIdMerchantCode(orderId, merchantCode);
				if (order == null) {
					throw PayExceptionCode.ORDER_NOT_FOUND.exp();
				}
				vo.setBusiId(order.getBusiId());
				break;
			}
			default:
				throw PayExceptionCode.QUERY_ERROR.exp();
			}
		}

		vo.setBusiType(params.getType().getType());
		vo.setStartDay(params.getStartDate());
		vo.setEndDay(params.getEndDate());
		vo.setAccountNo(params.getAccountNo());
		vo.setTradeState(params.getState());
		vo.setPageNo(params.getPageNo() == null ? "" : params.getPageNo().toString());
		vo.setPageSize(params.getPageSize() == null ? "" : params.getPageSize().toString());
		vo.setSignature(fuiouSignService.getSign(merchantCode, vo));
		return vo;
	}

	private FuiouQueryUserInfoReq buildQueryUserInfoVO(String merchantCode, QueryUserInfoReq params, FuiouDepositConfigExt extInfo) {
		FuiouQueryUserInfoReq vo = new FuiouQueryUserInfoReq();
		vo.setVersion(extInfo.getVersion());
		vo.setMerchantId(extInfo.getMerchantId());
		vo.setQueryBusiId(String.valueOf(System.nanoTime()));
		vo.setTradeDate(DateUtil.date2Str(new Date(), "yyyyMMdd"));
		vo.setAccountNos(params.getAccountNos());
		vo.setSignature(fuiouSignService.getSign(merchantCode, vo));
		return vo;
	}

	private QueryChangeCardVO buildReqParams(FuiouChangeCard order, FuiouDepositConfigExt extInfo) {
		QueryChangeCardVO vo = new QueryChangeCardVO();
		vo.setMerchantId(extInfo.getMerchantId());
		vo.setQueryBusiId(String.valueOf(System.nanoTime()));
		vo.setAccountNo(order.getAccountNo());
		vo.setBusiId(order.getBusiId());
		vo.setSignature(fuiouSignService.getSign(order.getMerchantCode(), vo));
		return vo;
	}

	@Override
	public UserRegisterVO queryUserInfo2(FuiouUserRegister po) throws Exception {
		final String op = "FuiouQueryServiceImpl.queryUserInfo";
		UserRegisterVO vo = UserRegisterVO.newInstance(po);

		// step1.判断订单是否出结果
		if (!vo.isQuery()) {
			logger.info(Log.op(op).msg("【富友存管用户信息查询】订单已经出结果，不再查询富友存管接口").kv("busiId", po.getBusiId()).toString());
			return vo;
		}

		// step2.如果订单未出结果，则调用富友存管查询用户信息接口
		PayRspCodeVO payRsp = fuiouDepositService.queryUserInfo(po.getBusiId(), po.getMerchantCode(), po.getPhone());

		// step3.根据响应参数更新订单信息
		if (PayExceptionCode.WARN_REQ_TIME_OUT.isCode(payRsp.getCode()) || PayExceptionCode.TO_CONFIRM.isCode(payRsp.getCode())) {
			return vo;
		}

		String state = FuiouDepositStateEnum.FAIL.getValue();
		int rspCode = payRsp.getCode();
		String rspMsg = payRsp.getDesc();

		if (PayExceptionCode.SUCCESS.isCode(payRsp.getCode())) {

			UserInfoResult result = (UserInfoResult) payRsp.getObj();
			String cardNo = CryptUtil.decrypt(po.getCardNoCip());
			String idNo = CryptUtil.decrypt(po.getIdNoCip());

			if (!StringUtils.equals(idNo, result.getIdNo()) || !StringUtils.equals(po.getCustomerName(), result.getAccountName())
					|| !StringUtils.equals(cardNo, result.getCardNo())) {
				// 在超时的情况下，用户注册存在并发的情况，需要判断法人名称 ，证件号，银行卡号一致性，如果不一致，则预警。且不更新数据库
				logger.error(Log.op(op).msg("【富友存管企业用户查询开户信息】查询开户信息成功，但是返回开户信息不一致，需要人工介入。").kv("UserInfoResult", result).kv("busiId", po.getBusiId())
						.toString());

				rspCode = PayExceptionCode.ERROR_PAY_FAIL.getCode();
				rspMsg = PayExceptionCode.ERROR_PAY_FAIL.getDesc();
			} else {
				// 更新订单处理状态为成功
				state = FuiouDepositStateEnum.SUCCESS.getValue();
				registerService.saveUserAuth(po.getMerchantCode(), po.getMerchantUserId(), CryptUtil.decrypt(po.getIdNoCip()), po.getCustomerName(),
						po.getBankCode(), CryptUtil.decrypt(po.getCardNoCip()), po.getPhone());
			}
		} else if (PayExceptionCode.ERROR_NOT_OPEN_ACCOUNT.isCode(payRsp.getCode())) {
			// 如果响应码为未开户,则初始化订单状态为"初始化"状态,等待业务下一次重调.edit by wangjw since 2.0.8
			state = FuiouDepositStateEnum.INI.getValue();
		}

		userRegisterDao.updateStateAndRspByBusiId(state, po.getBusiId(), DateUtil.getCurrentDateTime(), rspCode, rspMsg);

		po.setState(state);
		po.setRespCode(rspCode);
		po.setRespDesc(rspMsg);

		return vo;
	}

	@Override
	public QueryTransferChargeRsp queryTransferCharge(String merchantCode, QueryTransferChargeReq req) {
		final String op = "FuiouQueryServiceImpl.queryTransferCharge";
		try {
			FuiouDepositConfigExt depositConfig = fuiouSignService.getFuiouDepositConfig(merchantCode);
			// 构建请求
			FuiouQueryTransferChargeReq fuiouQueryReq = buildQueryTransferChargeReq(req, depositConfig);
			// 发请求
			QueryTransferChargeResultXMLRsp rsp = postForTransferChargeQuery(fuiouQueryReq, depositConfig);
			// 转换为结果信息
			QueryTransferChargeRsp response = transform(rsp);
			// 返回结果
			return response;
		} catch (PayException e) {
			throw e;
		} catch (Exception e) {
			logger.error(Log.op(op).msg("查询转账充值信息异常").kv("req", req).toString(), e);
			throw PayExceptionCode.WARN_UNKNOWN.exp();
		}
	}

	/**
	 * 转换为转账充值查询结果信息
	 *
	 * @author wujiande
	 * @date 2018-05-22 14:44:03
	 * @since v2.1.7
	 * @param fuiouRsp
	 * @return
	 */
	private QueryTransferChargeRsp transform(QueryTransferChargeResultXMLRsp fuiouRsp) {
		final String op = "FuiouQueryServiceImpl.transform";

		QueryTransferChargeRsp rsp = new QueryTransferChargeRsp();

		QueryTransferChargeResultXMLRsp.Plain plain = fuiouRsp.getPlain();
		// 校验查询是否成功
		if (!FuiouDepositRspCodeEnum.SUCCESS.isValue(plain.getRespCode())) {
			logger.error(Log.op(op).msg("返回状态异常").kv("response", fuiouRsp).toString());
			throw PayExceptionCode.WARN_UNKNOWN.expMsg(plain.getRespMsg());
		}

		// 拷贝总数
		rsp.setTotalNumber(plain.getTotalNumber());
		// 生成响应结果集
		List<QueryTransferChargeRsp.Result> results = new ArrayList<>();
		rsp.setResults(results);

		if (CollectionUtils.isEmpty(plain.getResults())) {
			return rsp;
		}

		for (QueryTransferChargeResultXMLRsp.QueryRst queryRst : plain.getResults()) {
			if (StringUtils.isNotEmpty(queryRst.getBusiId())) {
				results.add(buildQueryTransferChargeRspResult(queryRst, plain));
			}
		}
		return rsp;
	}

	/**
	 * 构建转账交易查询响应的交易信息
	 *
	 * @author wujiande
	 * @date 2018-05-25 16:06:37
	 * @since v2.1.7
	 * @param queryRst
	 * @param plain
	 * @return
	 */
	private QueryTransferChargeRsp.Result buildQueryTransferChargeRspResult(QueryTransferChargeResultXMLRsp.QueryRst queryRst,
			QueryTransferChargeResultXMLRsp.Plain plain) {
		QueryTransferChargeRsp.Result result = new QueryTransferChargeRsp.Result();
		if (queryRst.getAmount() != null) {
			result.setAmount(Long.toString(queryRst.getAmount()));
		}
		result.setReceiptTime(queryRst.getReceiptTime());
		result.setChargeCode(queryRst.getChargeCode());
		result.setAccountNo(queryRst.getAccountNo());
		result.setBusiId(queryRst.getBusiId());
		result.setState(queryRst.getStatus());
		result.setTradeTime(queryRst.getTradeDate());
		result.setUserName(queryRst.getAccountName());
		result.setRemark(queryRst.getRemark());
		// result.setRspCode(plain.getRespCode());
		// result.setRspMsg(plain.getRespMsg());

		// 根据busiId查询充值订单，并设置userId,since 2.2.8
		FuiouCharge fuiouCharge = fuiouChargeDao.selectByBusiId(queryRst.getBusiId());
		if (fuiouCharge != null) {
			result.setUserId(fuiouCharge.getUserId());
		}

		return result;
	}

	/**
	 * 发送转账充值查询请求
	 *
	 * @author wujiande
	 * @date 2018-05-22 13:36:30
	 * @since v2.1.7
	 * @param req
	 * @param depositConfig
	 * @return
	 */
	private QueryTransferChargeResultXMLRsp postForTransferChargeQuery(FuiouQueryTransferChargeReq req, FuiouDepositConfigExt depositConfig) {
		final String op = "FuiouQueryServiceImpl.postForTransferChargeQuery";
		String url = depositConfig.getQueryTransferChargeUrl();
		String jsonString = JSON.toJSONString(req);
		Map<String, String> params = JSON.parseObject(jsonString, strKV);
		String result = null;
		logger.info(Log.op(op).msg("【富友存管】发起HTTP请求").kv("url", url).kv("params", jsonString).toString());
		try {
			int connectTimeout = depositConfig.getConnectTimeout() <= 0 ? CONNECT_TIMEOUT : depositConfig.getConnectTimeout();
			int readTimeout = depositConfig.getReadTimeout() <= 0 ? READ_TIMEOUT : depositConfig.getReadTimeout();

			// 发送请求
			result = HttpUtil.postFormDirect(url, params, null, null, null, null, null, connectTimeout, readTimeout, true);
			logger.info(Log.op(op).msg("【富友存管】接收HTTP响应").kv("result", result).toString());

			// 响应为空异常
			if (StringUtils.isBlank(result)) {
				logger.error(Log.op(op).msg("【富友存管】存管接口返回数据异常!").kv("result", result).kv("params", jsonString).toString());
				throw PayExceptionCode.WARN_UNKNOWN.exp();
			}

			// 解析响应信息
			String plain = result.split("<plain>")[1].split("</plain>")[0];
			String signature = result.split("<signature>")[1].split("</signature>")[0];
			QueryTransferChargeResultXMLRsp rsp = QueryTransferChargeResultXMLRsp.fromXml(result);

			// 查询结果异常
			if (!FuiouDepositRspCodeEnum.SUCCESS.isValue(rsp.getPlain().getRespCode())) {
				logger.error(Log.op(op).msg("【富友存管】查询结果异常").kv("params", jsonString).kv("respCode", rsp.getPlain().getRespCode())
						.kv("respMsg", rsp.getPlain().getRespMsg()).toString());
				throw PayExceptionCode.WARN_UNKNOWN.expMsg(rsp.getPlain().getRespMsg());
			}

			// 验签异常
			if (!FuiouSignUtil.checkFuiouSignForQueryTransferCharge(plain, signature, depositConfig.getQueryTransferChargeKey())) {
				logger.error(Log.op(op).msg("【富友存管】存管接口返回参数验签错误!").kv("params", jsonString).kv("result", result).kv("params", jsonString).toString());
				throw PayExceptionCode.ERROR_SIGN_FAIL.exp();
			}

			return rsp;
		} catch (PayException e) {
			throw e;
		} catch (SocketTimeoutException e) {
			logger.error(Log.op(op).msg("【富友存管】存管接口请求超时!").kv("url", url).kv("params", jsonString).toString(), e);
			throw PayExceptionCode.WARN_REQ_TIME_OUT.exp();
		} catch (Exception e) {
			logger.error(Log.op(op).msg("【富友存管】存管接口未知异常!").kv("url", url).kv("params", jsonString).kv("result", result).toString(), e);
			throw PayExceptionCode.WARN_UNKNOWN.exp();
		}
	}

	/**
	 * 构建转账充值查询的请求参数
	 *
	 * @author wujiande
	 * @date 2018-05-22 13:36:06
	 * @since v2.1.7
	 * @param oriReq
	 * @param depositConfig
	 * @return
	 */
	private FuiouQueryTransferChargeReq buildQueryTransferChargeReq(QueryTransferChargeReq oriReq, FuiouDepositConfigExt depositConfig) {
		FuiouQueryTransferChargeReq fuiouReq = new FuiouQueryTransferChargeReq();
		fuiouReq.setMerchantId(depositConfig.getMerchantId());
		fuiouReq.setTranName(QUERY_TRANSFER_CHARGE_TRAN_NAME);
		fuiouReq.setBusiId(QUERY_TRANSFER_CHARGE_BUSI_ID_PRE + Calendar.getInstance().getTime().getTime());
		fuiouReq.setSrcBusiId(oriReq.getBusiId());
		fuiouReq.setChargeCode(oriReq.getChargeCode());
		if (StringUtils.isNotBlank(oriReq.getState())) {
			fuiouReq.setStatus(oriReq.getState());
		}

		fuiouReq.setStartTime(oriReq.getStartDate());
		fuiouReq.setEndTime(oriReq.getEndDate());
		fuiouReq.setPageNo(oriReq.getPageNo().toString());
		fuiouReq.setPageSize(oriReq.getPageSize().toString());
		fuiouReq.setVer("1.0.1");
		fuiouReq.setSign(FuiouSignUtil.createFuiouSignForQueryTransferCharge(fuiouReq, depositConfig.getQueryTransferChargeKey()));
		return fuiouReq;
	}

}
